package com.hsurosy.trigger.http;

import com.alibaba.fastjson.JSON;
import com.hsurosy.api.IRaffleStrategyService;
import com.hsurosy.api.dto.*;
import com.hsurosy.domain.activity.service.IRaffleActivityAccountQuotaService;
import com.hsurosy.domain.strategy.model.entity.RaffleAwardEntity;
import com.hsurosy.domain.strategy.model.entity.RaffleFactorEntity;
import com.hsurosy.domain.strategy.model.entity.StrategyAwardEntity;
import com.hsurosy.domain.strategy.model.valobj.RuleWeightVO;
import com.hsurosy.domain.strategy.service.IRaffleAward;
import com.hsurosy.domain.strategy.service.IRaffleRule;
import com.hsurosy.domain.strategy.service.IRaffleStrategy;
import com.hsurosy.domain.strategy.service.armory.IStrategyArmory;
import com.hsurosy.types.enums.ResponseCode;
import com.hsurosy.types.exception.AppException;
import com.hsurosy.types.model.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author Hsu琛君珩
 * @Date 2024-10-24 17:39
 * @Description 抽奖服务控制器
 * @Version: v1.0.0
 */
@Slf4j
@RestController()
@CrossOrigin("${app.config.cross-origin}")
@RequestMapping("/api/${app.config.api-version}/raffle/strategy")
public class RaffleStrategyController implements IRaffleStrategyService {

    @Resource
    private IStrategyArmory strategyArmory;  // 抽奖策略装配服务
    @Resource
    private IRaffleAward raffleAward;  // 抽奖奖品查询服务
    @Resource
    private IRaffleStrategy raffleStrategy;  // 抽奖策略服务
    @Resource
    private IRaffleRule raffleRule; // 抽奖规则服务
    @Resource
    private IRaffleActivityAccountQuotaService raffleActivityAccountQuotaService; // 抽奖活动账户配额服务

    /**
     * 装配抽奖策略，将策略信息装配到缓存中
     * 该接口通过指定策略ID来装配抽奖策略，并将策略相关信息写入缓存
     * 例如：可以通过访问链接 `/api/v1/raffle/strategy_armory` 来触发策略装配。
     *
     * @param strategyId 策略ID
     * @return 响应封装了装配结果（成功或失败）
     */
    @GetMapping(value = "/strategy_armory")
    @Override
    public Response<Boolean> strategyArmory(@RequestParam Long strategyId) {
        try {
            log.info("抽奖策略装配开始 strategyId: {}", strategyId);
            // 1. 调用策略装配服务，将策略装配到缓存中
            boolean armoryStatus = strategyArmory.assembleLotteryStrategy(strategyId);

            // 2. 构建并返回响应，包含装配结果
            Response<Boolean> response = Response.<Boolean>builder()
                    .code(ResponseCode.SUCCESS.getCode())  // 设置成功状态码
                    .info(ResponseCode.SUCCESS.getInfo())  // 设置成功提示信息
                    .data(armoryStatus)                    // 设置装配结果
                    .build();

            log.info("抽奖策略装配完成 strategyId: {} response: {}", strategyId, JSON.toJSONString(response));
            return response;
        } catch (Exception e) {
            // 3. 捕获异常，返回错误响应
            log.error("抽奖策略装配失败 strategyId: {}", strategyId, e);
            return Response.<Boolean>builder()
                    .code(ResponseCode.UN_ERROR.getCode())  // 设置错误状态码
                    .info(ResponseCode.UN_ERROR.getInfo())  // 设置错误提示信息
                    .build();
        }
    }

    /**
     * 查询抽奖奖品列表
     * 该接口允许客户端通过指定策略ID查询该策略下的奖品列表
     * 例如：客户端可以通过 POST 请求到 `/api/v1/raffle/query_raffle_award_list`，并提交 {"strategyId":100001} 这样的参数来查询奖品列表。
     *
     * @param request 包含策略ID的请求参数
     * @return 返回奖品列表的响应
     */
    @PostMapping(value = "/query_raffle_award_list")
    @Override
    public Response<List<RaffleAwardListResponseDTO>> queryRaffleAwardList(@RequestBody RaffleAwardListRequestDTO request) {
        try {
            log.info("查询抽奖奖品列表开始 userId: {} activityId: {}", request.getUserId(), request.getActivityId());
            // 1. 参数校验，确保用户ID和活动ID不为空
            if (StringUtils.isBlank(request.getUserId()) || null == request.getActivityId()) {
                throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
            }

            // 2. 查询奖品配置
            List<StrategyAwardEntity> strategyAwardEntities = raffleAward.queryRaffleStrategyAwardListByActivityId(request.getActivityId());

            // 3. 获取规则配置，查询奖品的解锁条件（需要抽奖多少次才能解锁）
            String[] treeIds = strategyAwardEntities.stream()
                    .map(StrategyAwardEntity::getRuleModels) // 获取规则模型ID
                    .filter(ruleModel -> ruleModel != null && !ruleModel.isEmpty()) // 过滤空的规则
                    .toArray(String[]::new);

            // 4. 查询规则配置 - 获取奖品的解锁限制，抽奖n次后解锁
            Map<String, Integer> ruleLockCountMap = raffleRule.queryAwardRuleLockCount(treeIds);

            // 5. 查询抽奖次数 - 用户当天参与的抽奖次数
            Integer dayPartakeCount = raffleActivityAccountQuotaService.queryRaffleActivityAccountDayPartakeCount(request.getActivityId(), request.getUserId());

            // 6. 遍历填充构建奖品列表响应数据
            List<RaffleAwardListResponseDTO> raffleAwardListResponseDTOS = new ArrayList<>(strategyAwardEntities.size());
            for (StrategyAwardEntity strategyAward : strategyAwardEntities) {
                Integer awardRuleLockCount = ruleLockCountMap.get(strategyAward.getRuleModels()); // 解锁条件
                raffleAwardListResponseDTOS.add(RaffleAwardListResponseDTO.builder()
                        .awardId(strategyAward.getAwardId()) // 奖品ID
                        .awardTitle(strategyAward.getAwardTitle()) // 奖品标题
                        .awardSubtitle(strategyAward.getAwardSubtitle()) // 奖品副标题
                        .sort(strategyAward.getSort()) // 奖品排序
                        .awardRuleLockCount(awardRuleLockCount) // 奖品解锁条件
                        .isAwardUnlock(null == awardRuleLockCount || dayPartakeCount >= awardRuleLockCount) // 奖品是否已解锁
                        .waitUnLockCount(null == awardRuleLockCount || awardRuleLockCount <= dayPartakeCount ? 0 : awardRuleLockCount - dayPartakeCount) // 剩余解锁次数
                        .build());
            }

            // 7. 构建成功响应结果并返回
            Response<List<RaffleAwardListResponseDTO>> response = Response.<List<RaffleAwardListResponseDTO>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(raffleAwardListResponseDTOS)
                    .build();

            log.info("查询抽奖奖品列表完成 userId: {} activityId: {} response: {}", request.getUserId(), request.getActivityId(), JSON.toJSONString(response));
            return response;
        } catch (Exception e) {
            // 8. 如果发生异常，返回错误响应
            log.error("查询抽奖奖品列表失败 userId: {} activityId: {}", request.getUserId(), request.getActivityId(), e);
            return Response.<List<RaffleAwardListResponseDTO>>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    /**
     * 查询策略抽奖权重规则
     *
     * @param request 请求对象，包含用户ID和活动ID
     * @return 返回包含权重规则配置及用户抽奖次数的响应对象
     * curl --request POST \
     * --url http://localhost:8091/api/v1/raffle/strategy/query_raffle_strategy_rule_weight \
     * --header 'content-type: application/json' \
     * --data '{
     * "userId":"xiaofuge",
     * "activityId": 100301
     */
    @PostMapping("/query_raffle_strategy_rule_weight")
    @Override
    public Response<List<RaffleStrategyRuleWeightResponseDTO>> queryRaffleStrategyRuleWeight(@RequestBody RaffleStrategyRuleWeightRequestDTO request) {
        try {
            log.info("查询抽奖策略权重规则配置开始 userId: {} activityId: {}", request.getUserId(), request.getActivityId());
            // 1. 参数校验：校验用户ID和活动ID是否有效
            if (StringUtils.isBlank(request.getUserId()) || null == request.getActivityId()) {
                throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
            }

            // 2. 查询用户在该活动中的总抽奖次数
            Integer userActivityAccountTotalUseCount = raffleActivityAccountQuotaService.queryRaffleActivityAccountPartakeCount(request.getActivityId(), request.getUserId());

            // 3. 查询抽奖策略权重规则列表
            List<RaffleStrategyRuleWeightResponseDTO> raffleStrategyRuleWeightList = new ArrayList<>();
            List<RuleWeightVO> ruleWeightVOList = raffleRule.queryAwardRuleWeightByActivityId(request.getActivityId());

            for (RuleWeightVO ruleWeightVO : ruleWeightVOList) {
                // 转换奖品列表为响应对象中的格式
                List<RaffleStrategyRuleWeightResponseDTO.StrategyAward> strategyAwards = new ArrayList<>();
                List<RuleWeightVO.Award> awardList = ruleWeightVO.getAwardList();
                for (RuleWeightVO.Award award : awardList) {
                    RaffleStrategyRuleWeightResponseDTO.StrategyAward strategyAward = new RaffleStrategyRuleWeightResponseDTO.StrategyAward();
                    strategyAward.setAwardId(award.getAwardId());
                    strategyAward.setAwardTitle(award.getAwardTitle());
                    strategyAwards.add(strategyAward);
                }

                // 封装单个权重规则的响应对象
                RaffleStrategyRuleWeightResponseDTO raffleStrategyRuleWeightResponseDTO = new RaffleStrategyRuleWeightResponseDTO();
                raffleStrategyRuleWeightResponseDTO.setRuleWeightCount(ruleWeightVO.getWeight());
                raffleStrategyRuleWeightResponseDTO.setStrategyAwards(strategyAwards);
                raffleStrategyRuleWeightResponseDTO.setUserActivityAccountTotalUseCount(userActivityAccountTotalUseCount);

                raffleStrategyRuleWeightList.add(raffleStrategyRuleWeightResponseDTO);
            }

            // 构建响应对象
            Response<List<RaffleStrategyRuleWeightResponseDTO>> response = Response.<List<RaffleStrategyRuleWeightResponseDTO>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(raffleStrategyRuleWeightList)
                    .build();

            log.info("查询抽奖策略权重规则配置完成 userId: {} activityId: {} response: {}", request.getUserId(), request.getActivityId(), JSON.toJSONString(response));
            return response;
        } catch (Exception e) {
            log.error("查询抽奖策略权重规则配置完成 userId: {} activityId: {}", request.getUserId(), request.getActivityId(), e);
            return Response.<List<RaffleStrategyRuleWeightResponseDTO>>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    /**
     * 随机抽奖接口
     * 该接口允许客户端通过指定策略ID来执行随机抽奖操作
     * 例如：客户端可以通过 POST 请求到 `/api/v1/raffle/random_raffle` 并提交 {"strategyId":100001} 来进行随机抽奖。
     *
     * @param requestDTO 包含策略ID的请求参数
     * @return 返回抽奖结果，包含抽中的奖品ID和奖品序列
     */
    @PostMapping(value = "/random_raffle")
    @Override
    public Response<RaffleStrategyResponseDTO> randomRaffle(@RequestBody RaffleStrategyRequestDTO requestDTO) {
        try {
            log.info("随机抽奖开始 strategyId: {}", requestDTO.getStrategyId());

            // 1. 调用抽奖策略进行抽奖操作，并返回抽中的奖品信息
            RaffleAwardEntity raffleAwardEntity = raffleStrategy.performRaffle(RaffleFactorEntity.builder()
                    .userId("system")  // 示例中假设用户ID为 "system"
                    .strategyId(requestDTO.getStrategyId())  // 设置抽奖策略ID
                    .build());

            // 2. 封装抽奖结果，将抽中的奖品信息返回给客户端
            Response<RaffleStrategyResponseDTO> response = Response.<RaffleStrategyResponseDTO>builder()
                    .code(ResponseCode.SUCCESS.getCode())   // 设置成功状态码
                    .info(ResponseCode.SUCCESS.getInfo())   // 设置成功信息
                    .data(RaffleStrategyResponseDTO.builder()       // 构建返回的抽奖结果
                            .awardId(raffleAwardEntity.getAwardId())  // 抽中的奖品ID
                            .awardIndex(raffleAwardEntity.getSort())  // 奖品排序
                            .build())
                    .build();

            log.info("随机抽奖完成 strategyId: {} response: {}", requestDTO.getStrategyId(), JSON.toJSONString(response));
            return response;
        } catch (AppException e) {
            // 3. 如果捕获到应用程序异常，返回自定义错误信息
            log.error("随机抽奖失败 strategyId: {} {}", requestDTO.getStrategyId(), e.getInfo());
            return Response.<RaffleStrategyResponseDTO>builder()
                    .code(e.getCode())   // 设置异常状态码
                    .info(e.getInfo())   // 设置异常信息
                    .build();
        } catch (Exception e) {
            // 4. 捕获其他异常，返回系统级错误信息
            log.info("随机抽奖失败 strategyId: {}", requestDTO.getStrategyId(), e);
            return Response.<RaffleStrategyResponseDTO>builder()
                    .code(ResponseCode.UN_ERROR.getCode())  // 设置未知错误的状态码
                    .info(ResponseCode.UN_ERROR.getInfo())  // 设置错误信息
                    .build();
        }
    }

}
